

<!DOCTYPE html>
<html lang="zh-CN" data-default-color-scheme=auto>



<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/img/favicon.png">
  <link rel="icon" href="/img/favicon.png">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="description" content="Blue~u~u~u">
  <meta name="author" content="Blue~u~u~u">
  <meta name="keywords" content="">
  <meta name="description" content="Mybatis-plus常用注解及插件（二）一、@TableNamevalue属性实体类的名字是User，数据库表名是t_user 1234@TableName(value &#x3D; &quot;t_user&quot;)public class User &amp;#123;    &#x2F;&#x2F;...&amp;#125;  二、@TableId1、雪花算法默认情况下数据库的id列使用的是基于雪花算法的策略生成  背景随着业务">
<meta property="og:type" content="article">
<meta property="og:title" content="Mybatis-plus常用注解及插件（二）">
<meta property="og:url" content="http://www.slx.blue/2022/01/20/MybatisPlus02/index.html">
<meta property="og:site_name" content="Blue~u~u~u~u">
<meta property="og:description" content="Mybatis-plus常用注解及插件（二）一、@TableNamevalue属性实体类的名字是User，数据库表名是t_user 1234@TableName(value &#x3D; &quot;t_user&quot;)public class User &amp;#123;    &#x2F;&#x2F;...&amp;#125;  二、@TableId1、雪花算法默认情况下数据库的id列使用的是基于雪花算法的策略生成  背景随着业务">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/MybatisPlus/28639f20-f8c8-451f-917b-a8abfd21bc07.png">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/MybatisPlus/373ba7ef41999b4cc090e5aaee3bc63b_2.png">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/MybatisPlus/665ae40a-443f-4356-bb5d-4742f947c430.jpg">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/MybatisPlus/05094d95-9e68-4085-86bf-b023fc7d2eac.png">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/MybatisPlus/b2abe1b5-3b61-451c-9a59-bca3980e9766.png">
<meta property="og:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/MybatisPlus/fd2d6e00-f33e-4d84-8ca2-7fd0062b55b3.png">
<meta property="article:published_time" content="2022-01-20T02:55:37.000Z">
<meta property="article:modified_time" content="2022-01-20T02:57:43.189Z">
<meta property="article:author" content="Blue~u~u~u">
<meta property="article:tag" content="MybatisPlus">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://lllong.oss-cn-shenzhen.aliyuncs.com/MybatisPlus/28639f20-f8c8-451f-917b-a8abfd21bc07.png">
  
  <title>Mybatis-plus常用注解及插件（二） - Blue~u~u~u~u</title>

  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4/dist/css/bootstrap.min.css" />


  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/github-markdown-css@4/github-markdown.min.css" />
  <link  rel="stylesheet" href="/lib/hint/hint.min.css" />

  
    
    
      
      <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/highlight.js@10/styles/github-gist.min.css" />
    
  

  
    <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3/dist/jquery.fancybox.min.css" />
  


<!-- 主题依赖的图标库，不要自行修改 -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_ba1fz6golrf.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_kmeydafke9r.css">


<link  rel="stylesheet" href="/css/main.css" />

<!-- 自定义样式保持在最底部 -->


  <script id="fluid-configs">
    var Fluid = window.Fluid || {};
    var CONFIG = {"hostname":"www.slx.blue","root":"/","version":"1.8.12","typing":{"enable":true,"typeSpeed":180,"cursorChar":"_","loop":true},"anchorjs":{"enable":true,"element":"h1,h2,h3,h4,h5,h6","placement":"right","visible":"hover","icon":""},"progressbar":{"enable":true,"height_px":3,"color":"#29d","options":{"showSpinner":false,"trickleSpeed":100}},"copy_btn":true,"image_zoom":{"enable":true,"img_url_replace":["",""]},"toc":{"enable":true,"headingSelector":"h1,h2,h3,h4,h5,h6","collapseDepth":0},"lazyload":{"enable":true,"loading_img":"/img/loading.gif","onlypost":false,"offset_factor":2},"web_analytics":{"enable":false,"baidu":null,"google":null,"gtag":null,"tencent":{"sid":null,"cid":null},"woyaola":null,"cnzz":null,"leancloud":{"app_id":null,"app_key":null,"server_url":null,"path":"window.location.pathname"}},"search_path":"/local-search.xml"};
  </script>
  <script  src="/js/utils.js" ></script>
  <script  src="/js/color-schema.js" ></script>
<meta name="generator" content="Hexo 5.4.0"></head>

<script src="https://cdn.jsdelivr.net/npm/jquery/dist/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/font-awesome/css/font-awesome.min.css"/>
<script src="/live2d-widget/autoload.js"></script>


<body>
  <header style="height: 70vh;">
    <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand" href="/">
      <strong>Blue~u~u</strong>
    </a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/">
                <i class="iconfont icon-home-fill"></i>
                首页
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/archives/">
                <i class="iconfont icon-archive-fill"></i>
                归档
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/categories/">
                <i class="iconfont icon-category-fill"></i>
                分类
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/tags/">
                <i class="iconfont icon-tags-fill"></i>
                标签
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/about/">
                <i class="iconfont icon-user-fill"></i>
                关于
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/links/">
                <i class="iconfont icon-link-fill"></i>
                友链
              </a>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" target="_self" href="javascript:;" data-toggle="modal" data-target="#modalSearch" aria-label="Search">
              &nbsp;<i class="iconfont icon-search"></i>&nbsp;
            </a>
          </li>
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" target="_self" href="javascript:;" aria-label="Color Toggle">&nbsp;<i
                class="iconfont icon-dark" id="color-toggle-icon"></i>&nbsp;</a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

    <div class="banner" id="banner" parallax=true
         style="background: url('/images/default.png') no-repeat center center;
           background-size: cover;">
      <div class="full-bg-img">
        <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
          <div class="page-header text-center fade-in-up">
            <span class="h2" id="subtitle" title="Mybatis-plus常用注解及插件（二）">
              
            </span>

            
              <div class="mt-3">
  
  
    <span class="post-meta">
      <i class="iconfont icon-date-fill" aria-hidden="true"></i>
      <time datetime="2022-01-20 10:55" pubdate>
        2022年1月20日 上午
      </time>
    </span>
  
</div>

<div class="mt-1">
  
    <span class="post-meta mr-2">
      <i class="iconfont icon-chart"></i>
      7.5k 字
    </span>
  

  
    <span class="post-meta mr-2">
      <i class="iconfont icon-clock-fill"></i>
      
      
      23 分钟
    </span>
  

  
  
    
      <!-- 不蒜子统计文章PV -->
      <span id="busuanzi_container_page_pv" style="display: none">
        <i class="iconfont icon-eye" aria-hidden="true"></i>
        <span id="busuanzi_value_page_pv"></span> 次
      </span>
    
  
</div>

            
          </div>

          
        </div>
      </div>
    </div>
  </header>

  <main>
    
      

<div class="container-fluid nopadding-x">
  <div class="row nomargin-x">
    <div class="d-none d-lg-block col-lg-2"></div>
    <div class="col-lg-8 nopadding-x-md">
      <div class="container nopadding-x-md" id="board-ctn">
        <div class="py-5" id="board">
          <article class="post-content mx-auto">
            <!-- SEO header -->
            <h1 style="display: none">Mybatis-plus常用注解及插件（二）</h1>
            
              <p class="note note-info">
                
                  本文最后更新于：4 个月前
                
              </p>
            
            <div class="markdown-body">
              <h1 id="Mybatis-plus常用注解及插件（二）"><a href="#Mybatis-plus常用注解及插件（二）" class="headerlink" title="Mybatis-plus常用注解及插件（二）"></a>Mybatis-plus常用注解及插件（二）</h1><h1 id="一、-TableName"><a href="#一、-TableName" class="headerlink" title="一、@TableName"></a><strong>一、@TableName</strong></h1><h2 id="value属性"><a href="#value属性" class="headerlink" title="value属性"></a>value属性</h2><p>实体类的名字是User，数据库表名是t_user</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@TableName(value = &quot;t_user&quot;)</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> </span>&#123;<br>    <span class="hljs-comment">//...</span><br>&#125;<br></code></pre></td></tr></table></figure>

<h1 id="二、-TableId"><a href="#二、-TableId" class="headerlink" title="二、@TableId"></a><strong>二、@TableId</strong></h1><h2 id="1、雪花算法"><a href="#1、雪花算法" class="headerlink" title="1、雪花算法"></a>1、雪花算法</h2><p>默认情况下数据库的id列使用的是基于雪花算法的策略生成</p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/MybatisPlus/28639f20-f8c8-451f-917b-a8abfd21bc07.png" srcset="/img/loading.gif" lazyload alt="img"></p>
<h3 id="背景"><a href="#背景" class="headerlink" title="背景"></a><strong>背景</strong></h3><p>随着业务规模的不断扩大，需要选择合适的方案去应对数据规模的增长，以应对逐渐增长的访问压力和数据量。</p>
<p>数据库的扩展方式主要包括：业务分库、主从复制，数据库分表。</p>
<h3 id="数据库分表"><a href="#数据库分表" class="headerlink" title="数据库分表"></a>数据库分表</h3><p>将不同业务数据分散存储到不同的数据库服务器，能够支撑百万甚至千万用户规模的业务，但如果业务继续发展，同一业务的单表数据也会达到单台数据库服务器的处理瓶颈。例如，淘宝的几亿用户数据，如果全部存放在一台数据库服务器的一张表中，肯定是无法满足性能要求的，此时就需要对单表数据进行拆分。</p>
<p>单表数据拆分有两种方式：垂直分表和水平分表。示意图如下：</p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/MybatisPlus/373ba7ef41999b4cc090e5aaee3bc63b_2.png" srcset="/img/loading.gif" lazyload alt="img"></p>
<p><strong>垂直分表：</strong></p>
<ul>
<li>垂直分表适合将表中某些不常用且占了大量空间的列拆分出去。</li>
<li><strong>例如，</strong>前面示意图中的 nickname 和 description 字段，假设我们是一个婚恋网站，用户在筛选其他用户的时候，主要是用 age 和 sex 两个字段进行查询，而 nickname 和 description 两个字段主要用于展示，一般不会在业务查询中用到。description 本身又比较长，因此我们可以将这两个字段独立到另外一张表中，这样在查询 age 和 sex 时，就能带来一定的性能提升。</li>
</ul>
<p><strong>水平分表：</strong></p>
<ul>
<li>水平分表适合表行数特别大的表，有的公司要求单表行数超过 5000 万就必须进行分表，这个数字可以作为参考，但并不是绝对标准，关键还是要看表的访问性能。对于一些比较复杂的表，可能超过 1000 万就要分表了；而对于一些简单的表，即使存储数据超过 1 亿行，也可以不分表。</li>
<li>但不管怎样，当看到表的数据量达到千万级别时，作为架构师就要警觉起来，因为这很可能是架构的性能瓶颈或者隐患。</li>
</ul>
<p>水平分表相比垂直分表，会引入更多的复杂性，例如数据id：</p>
<p><strong>主键自增：</strong></p>
<ul>
<li>以最常见的用户 ID 为例，可以按照 1000000 的范围大小进行分段，1 ~ 999999 放到表 1中，1000000 ~ 1999999 放到表2中，以此类推。</li>
<li>复杂点：分段大小的选取。分段太小会导致切分后子表数量过多，增加维护复杂度；分段太大可能会导致单表依然存在性能问题，一般建议分段大小在 100 万至 2000 万之间，具体需要根据业务选取合适的分段大小。</li>
<li>优点：可以随着数据的增加平滑地扩充新的表。例如，现在的用户是 100 万，如果增加到 1000 万，只需要增加新的表就可以了，原有的数据不需要动。</li>
<li>缺点：分布不均匀。假如按照 1000 万来进行分表，有可能某个分段实际存储的数据量只有 1 条，而另外一个分段实际存储的数据量有 1000 万条。</li>
</ul>
<p><strong>Hash ：</strong></p>
<ul>
<li>同样以用户 ID 为例，假如我们一开始就规划了 10 个数据库表，可以简单地用 user_id % 10 的值来表示数据所属的数据库表编号，ID 为 985 的用户放到编号为 5 的子表中，ID 为 10086 的用户放到编号为 6 的子表中。</li>
<li>复杂点：初始表数量的确定。表数量太多维护比较麻烦，表数量太少又可能导致单表性能存在问题。</li>
<li>优点：表分布比较均匀。</li>
<li>缺点：扩充新的表很麻烦，所有数据都要重分布。</li>
<li></li>
</ul>
<p><em><strong>*雪花算法：*</strong></em></p>
<p>雪花算法是由Twitter公布的分布式主键生成算法，它能够保证不同表的主键的不重复性，以及相同表的主键的有序性。</p>
<ul>
<li><p>核心思想：</p>
</li>
<li><ul>
<li>长度共64bit（一个long型）。</li>
<li>首先是一个符号位，1bit标识，由于long基本类型在Java中是带符号的，最高位是符号位，正数是0，负数是1，所以id一般是正数，最高位是0。</li>
<li>41bit时间截(毫秒级)，存储的是时间截的差值（当前时间截 - 开始时间截)，结果约等于69.73年。</li>
<li>10bit作为机器的ID（5个bit是数据中心，5个bit的机器ID，可以部署在1024个节点）。</li>
<li>12bit作为毫秒内的流水号（意味着每个节点在每毫秒可以产生 4096 个 ID）。</li>
</ul>
</li>
</ul>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/MybatisPlus/665ae40a-443f-4356-bb5d-4742f947c430.jpg" srcset="/img/loading.gif" lazyload alt="img"></p>
<ul>
<li>优点：整体上按照时间自增排序，并且整个分布式系统内不会产生ID碰撞，并且效率较高。</li>
</ul>
<h2 id="2、指定主键列"><a href="#2、指定主键列" class="headerlink" title="2、指定主键列"></a>2、指定主键列</h2><ul>
<li>测试：将数据库表中的id列改为 uid，将实体类中的id属性改成 uid，执行数据插入，则报告如下错误</li>
</ul>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/MybatisPlus/05094d95-9e68-4085-86bf-b023fc7d2eac.png" srcset="/img/loading.gif" lazyload alt="img"></p>
<ul>
<li>原因：因为MP默认认为<strong>id</strong>是主键列，其他名字的属性MP无法默认自动填充</li>
<li>解决方案：为主键列添加 @TableId 注解</li>
</ul>
<h2 id="3、type属性"><a href="#3、type属性" class="headerlink" title="3、type属性"></a>3、type属性</h2><p>type属性用来定义主键策略</p>
<ul>
<li><strong>IdType.ASSIGN_ID：</strong>使用基于雪花算法的策略生成数据id</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@TableId(type = IdType.ASSIGN_ID)</span><br><span class="hljs-keyword">private</span> Long id;<br></code></pre></td></tr></table></figure>

<p>注意：当对象的id被明确赋值时，不会使用雪花算法</p>
<ul>
<li><strong>IdType.AUTO：</strong>使用数据库的自增策略</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@TableId(type = IdType.AUTO)</span><br><span class="hljs-keyword">private</span> Long id;<br></code></pre></td></tr></table></figure>

<p>注意：该类型请确保数据库设置了 ID自增 否则无效</p>
<ul>
<li><strong>全局配置：</strong>要想影响所有实体的配置，可以设置全局主键配置</li>
</ul>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs properties"><span class="hljs-comment">#全局设置主键生成策略</span><br><span class="hljs-meta">mybatis-plus.global-config.db-config.id-type</span>=<span class="hljs-string">auto</span><br></code></pre></td></tr></table></figure>

<h1 id="三、-TableField"><a href="#三、-TableField" class="headerlink" title="三、@TableField"></a>三、@TableField</h1><h2 id="1、value属性"><a href="#1、value属性" class="headerlink" title="1、value属性"></a>1、value属性</h2><p>功能同TableId的value属性</p>
<p>注意：MP会自动将数据库中的下划线命名风格转化为实体类中的驼峰命名风格</p>
<p><strong>例如，</strong>数据库中的列 create_time 和 update_time 自动对应实体类中的 createTime 和 updateTime</p>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/MybatisPlus/b2abe1b5-3b61-451c-9a59-bca3980e9766.png" srcset="/img/loading.gif" lazyload alt="img"></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">private</span> LocalDateTime createTime;<br><span class="hljs-keyword">private</span> LocalDateTime updateTime;<br></code></pre></td></tr></table></figure>

<p>扩展知识：为什么建议使用你 LocalDateTime ，而不是 Date？<a target="_blank" rel="noopener" href="https://zhuanlan.zhihu.com/p/87555377">https://zhuanlan.zhihu.com/p/87555377</a></p>
<ul>
<li>java.util.Date的大多数方法已经过时</li>
<li>java.util.Date的输出可读性差</li>
<li>java.util.Date对应的格式化类SimpleDateFormat是线程不安全的类。阿里巴巴开发手册中禁用static修饰SimpleDateFormat。</li>
<li>LocalDateTime 对应的格式化类DateTimeFormatter是线程安全的</li>
</ul>
<h2 id="2、自动填充"><a href="#2、自动填充" class="headerlink" title="2、自动填充"></a>2、自动填充</h2><p><strong>需求描述：</strong></p>
<p>项目中经常会遇到一些数据，每次都使用相同的方式填充，例如记录的创建时间，更新时间等。我们可以使用MyBatis Plus的自动填充功能，完成这些字段的赋值工作。</p>
<p><strong>例如，</strong>阿里巴巴的开发手册中建议每个数据库表必须要有create_time 和 update_time字段，我们可以使用自动填充功能维护这两个字段</p>
<ul>
<li><strong>step1：</strong>添加fill属性</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@TableField(fill = FieldFill.INSERT)</span><br><span class="hljs-keyword">private</span> LocalDateTime createTime;<br><span class="hljs-meta">@TableField(fill = FieldFill.INSERT_UPDATE)</span><br><span class="hljs-keyword">private</span> LocalDateTime updateTime;<br></code></pre></td></tr></table></figure>

<ul>
<li><strong>step2：</strong>实现元对象处理器接口 -&gt; 创建handler包，创建MyMetaObjectHandler类</li>
</ul>
<p>注意：不要忘记添加 @Component 注解</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Slf4j</span><br><span class="hljs-meta">@Component</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyMetaObjectHandler</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">MetaObjectHandler</span> </span>&#123;<br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">insertFill</span><span class="hljs-params">(MetaObject metaObject)</span> </span>&#123;<br>        log.info(<span class="hljs-string">&quot;start insert fill ....&quot;</span>);<br>        <span class="hljs-keyword">this</span>.strictInsertFill(metaObject, <span class="hljs-string">&quot;createTime&quot;</span>, LocalDateTime.class, LocalDateTime.now());<br>        <span class="hljs-keyword">this</span>.strictInsertFill(metaObject, <span class="hljs-string">&quot;updateTime&quot;</span>, LocalDateTime.class, LocalDateTime.now());<br>    &#125;<br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">updateFill</span><span class="hljs-params">(MetaObject metaObject)</span> </span>&#123;<br>        log.info(<span class="hljs-string">&quot;start update fill ....&quot;</span>);<br>        <span class="hljs-keyword">this</span>.strictUpdateFill(metaObject, <span class="hljs-string">&quot;updateTime&quot;</span>, LocalDateTime.class, LocalDateTime.now());<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<h2 id="3、测试"><a href="#3、测试" class="headerlink" title="3、测试"></a>3、测试</h2><ul>
<li><p>测试新增</p>
</li>
<li><p>测试修改</p>
</li>
<li><p>避免自动填充时开销过大，填充前先判断当前对象中是否有相关属性</p>
</li>
</ul>
<h1 id="四、-TableLogic"><a href="#四、-TableLogic" class="headerlink" title="四、@TableLogic"></a>四、@TableLogic</h1><h2 id="1、逻辑删除"><a href="#1、逻辑删除" class="headerlink" title="1、逻辑删除"></a>1、逻辑删除</h2><ul>
<li>物理删除：真实删除，将对应数据从数据库中删除，之后查询不到此条被删除的数据</li>
<li>逻辑删除：假删除，将对应数据中代表是否被删除字段的状态修改为“被删除状态”，之后在数据库中仍旧能看到此条数据记录</li>
</ul>
<p>使用场景：可以进行数据恢复</p>
<h2 id="2、实现逻辑删除"><a href="#2、实现逻辑删除" class="headerlink" title="2、实现逻辑删除"></a>2、实现逻辑删除</h2><ul>
<li><strong>step1：</strong>数据库中创建逻辑删除状态列</li>
</ul>
<p><img src="https://lllong.oss-cn-shenzhen.aliyuncs.com/MybatisPlus/fd2d6e00-f33e-4d84-8ca2-7fd0062b55b3.png" srcset="/img/loading.gif" lazyload alt="img"></p>
<ul>
<li><strong>step2：</strong>实体类中添加逻辑删除属性</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@TableLogic</span><br><span class="hljs-meta">@TableField(value = &quot;is_deleted&quot;)</span><br><span class="hljs-keyword">private</span> Integer deleted;<br></code></pre></td></tr></table></figure>

<h2 id="3、测试-1"><a href="#3、测试-1" class="headerlink" title="3、测试"></a>3、测试</h2><ul>
<li>测试删除：删除功能被转变为更新功能</li>
</ul>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-comment">-- 实际执行的SQL</span><br>update <span class="hljs-keyword">user</span> <span class="hljs-keyword">set</span> is_deleted<span class="hljs-operator">=</span><span class="hljs-number">1</span> <span class="hljs-keyword">where</span> id <span class="hljs-operator">=</span> <span class="hljs-number">1</span> <span class="hljs-keyword">and</span> is_deleted<span class="hljs-operator">=</span><span class="hljs-number">0</span><br></code></pre></td></tr></table></figure>

<ul>
<li>测试查询：被逻辑删除的数据默认不会被查询</li>
</ul>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-comment">-- 实际执行的SQL</span><br><span class="hljs-keyword">select</span> id,name,is_deleted <span class="hljs-keyword">from</span> <span class="hljs-keyword">user</span> <span class="hljs-keyword">where</span> is_deleted<span class="hljs-operator">=</span><span class="hljs-number">0</span><br></code></pre></td></tr></table></figure>

<h1 id="五、分页插件"><a href="#五、分页插件" class="headerlink" title="五、分页插件"></a>五、分页插件</h1><p>MyBatis Plus自带分页插件，只要简单的配置即可实现分页功能</p>
<h2 id="1、添加配置类"><a href="#1、添加配置类" class="headerlink" title="1、添加配置类"></a>1、添加配置类</h2><p>创建config包，创建MybatisPlusConfig类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Configuration</span><br><span class="hljs-meta">@MapperScan(&quot;com.atguigu.mybatisplus.mapper&quot;)</span>  <span class="hljs-comment">//可以将主类中的注解移到此处</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MybatisPlusConfig</span> </span>&#123;<br>&#125;<br></code></pre></td></tr></table></figure>

<h2 id="2、添加分页插件"><a href="#2、添加分页插件" class="headerlink" title="2、添加分页插件"></a><strong>2、添加分页插件</strong></h2><p>配置类中添加@Bean配置</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Bean</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> MybatisPlusInterceptor <span class="hljs-title">mybatisPlusInterceptor</span><span class="hljs-params">()</span> </span>&#123;<br>    MybatisPlusInterceptor interceptor = <span class="hljs-keyword">new</span> MybatisPlusInterceptor();<br>    interceptor.addInnerInterceptor(<span class="hljs-keyword">new</span> PaginationInnerInterceptor(DbType.MYSQL));<br>    <span class="hljs-keyword">return</span> interceptor;<br>&#125;<br></code></pre></td></tr></table></figure>

<h2 id="3、测试分页"><a href="#3、测试分页" class="headerlink" title="3、测试分页"></a><strong>3、测试分页</strong></h2><p>创建类InterceptorTests</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@SpringBootTest</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">InterceptorTests</span> </span>&#123;<br>    <span class="hljs-meta">@Resource</span><br>    <span class="hljs-keyword">private</span> UserMapper userMapper;<br>    <span class="hljs-meta">@Test</span><br>    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">testSelectPage</span><span class="hljs-params">()</span></span>&#123;<br>        <span class="hljs-comment">//创建分页参数</span><br>        Page&lt;User&gt; pageParam = <span class="hljs-keyword">new</span> Page&lt;&gt;(<span class="hljs-number">1</span>,<span class="hljs-number">5</span>);<br>        <span class="hljs-comment">//执行分页查询</span><br>        userMapper.selectPage(pageParam, <span class="hljs-keyword">null</span>);<br>        <span class="hljs-comment">//查看分页参数的成员</span><br>        System.out.println(pageParam);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<h1 id="六、XML自定义分页"><a href="#六、XML自定义分页" class="headerlink" title="六、XML自定义分页"></a>六、XML自定义分页</h1><h2 id="1、UserMapper中定义接口方法"><a href="#1、UserMapper中定义接口方法" class="headerlink" title="1、UserMapper中定义接口方法"></a>1、UserMapper中定义接口方法</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 查询 : 根据年龄查询用户列表，分页显示</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> page 分页对象,xml中可以从里面进行取值,传递参数 Page 即自动分页,必须放在第一位</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> age 年龄</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span> 分页对象</span><br><span class="hljs-comment">     */</span><br><span class="hljs-function">IPage&lt;User&gt; <span class="hljs-title">selectPageByPage</span><span class="hljs-params">(Page&lt;?&gt; page, Integer age)</span></span>;<br></code></pre></td></tr></table></figure>

<h2 id="2、定义XML"><a href="#2、定义XML" class="headerlink" title="2、定义XML"></a>2、定义XML</h2><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-name">select</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;selectPageByPage&quot;</span> <span class="hljs-attr">resultType</span>=<span class="hljs-string">&quot;com.atguigu.mybatisplus.entity.User&quot;</span>&gt;</span><br>    SELECT <span class="hljs-tag">&lt;<span class="hljs-name">include</span> <span class="hljs-attr">refid</span>=<span class="hljs-string">&quot;Base_Column_List&quot;</span>/&gt;</span> FROM user WHERE age &gt; #&#123;age&#125;<br><span class="hljs-tag">&lt;/<span class="hljs-name">select</span>&gt;</span><br></code></pre></td></tr></table></figure>

<h2 id="3、测试-2"><a href="#3、测试-2" class="headerlink" title="3、测试"></a>3、测试</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Test</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">testSelectPageVo</span><span class="hljs-params">()</span></span>&#123;<br>    Page&lt;User&gt; pageParam = <span class="hljs-keyword">new</span> Page&lt;&gt;(<span class="hljs-number">1</span>,<span class="hljs-number">5</span>);<br>    userMapper.selectPageByPage(pageParam, <span class="hljs-number">18</span>);<br>    List&lt;User&gt; users = pageParam.getRecords();<br>    users.forEach(System.out::println);<br>&#125;<br></code></pre></td></tr></table></figure>

<h1 id="七、乐观锁"><a href="#七、乐观锁" class="headerlink" title="七、乐观锁"></a><strong>七、乐观锁</strong></h1><h2 id="1、场景"><a href="#1、场景" class="headerlink" title="1、场景"></a><strong>1、场景</strong></h2><p>一件商品，成本价是80元，售价是100元。老板先是通知小李，说你去把商品价格增加50元。小李正在玩游戏，耽搁了一个小时。正好一个小时后，老板觉得商品价格增加到150元，价格太高，可能会影响销量。又通知小王，你把商品价格降低30元。</p>
<p>此时，小李和小王同时操作商品后台系统。小李操作的时候，系统先取出商品价格100元；小王也在操作，取出的商品价格也是100元。小李将价格加了50元，并将100+50=150元存入了数据库；小王将商品减了30元，并将100-30=70元存入了数据库。是的，如果没有锁，小李的操作就完全被小王的覆盖了。</p>
<p>现在商品价格是70元，比成本价低10元。几分钟后，这个商品很快出售了1千多件商品，老板亏1万多。</p>
<p>接下来将我们演示这一过程：</p>
<p><strong>step1：数据库中增加商品表</strong></p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> product<br>(<br>    id <span class="hljs-type">BIGINT</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> AUTO_INCREMENT COMMENT <span class="hljs-string">&#x27;主键ID&#x27;</span>,<br>    name <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">30</span>) <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;商品名称&#x27;</span>,<br>    price <span class="hljs-type">INT</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span> COMMENT <span class="hljs-string">&#x27;价格&#x27;</span>,<br>    version <span class="hljs-type">INT</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span> COMMENT <span class="hljs-string">&#x27;乐观锁版本号&#x27;</span>,<br>    <span class="hljs-keyword">PRIMARY</span> KEY (id)<br>);<br><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> product (id, NAME, price) <span class="hljs-keyword">VALUES</span> (<span class="hljs-number">1</span>, <span class="hljs-string">&#x27;笔记本&#x27;</span>, <span class="hljs-number">100</span>);<br></code></pre></td></tr></table></figure>

<p><strong>step2：创建实体类</strong></p>
<h3 id><a href="#" class="headerlink" title></a></h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Data</span><br><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Product</span> </span>&#123;<br>    <span class="hljs-keyword">private</span> Long id;<br>    <span class="hljs-keyword">private</span> String name;<br>    <span class="hljs-keyword">private</span> Integer price;<br>    <span class="hljs-keyword">private</span> Integer version;<br>&#125;<br></code></pre></td></tr></table></figure>

<p><strong>step3：创建Mapper</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">ProductMapper</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">BaseMapper</span>&lt;<span class="hljs-title">Product</span>&gt; </span>&#123;<br>    <br>&#125;<br></code></pre></td></tr></table></figure>

<p><strong>step4：测试</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Resource</span><br><span class="hljs-keyword">private</span> ProductMapper productMapper;<br><span class="hljs-meta">@Test</span><br><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">testConcurrentUpdate</span><span class="hljs-params">()</span> </span>&#123;<br>    <span class="hljs-comment">//1、小李</span><br>    Product p1 = productMapper.selectById(<span class="hljs-number">1L</span>);<br>    <span class="hljs-comment">//2、小王</span><br>    Product p2 = productMapper.selectById(<span class="hljs-number">1L</span>);<br>    <span class="hljs-comment">//3、小李将价格加了50元，存入了数据库</span><br>    p1.setPrice(p1.getPrice() + <span class="hljs-number">50</span>);<br>    <span class="hljs-keyword">int</span> result1 = productMapper.updateById(p1);<br>    System.out.println(<span class="hljs-string">&quot;小李修改结果：&quot;</span> + result1);<br>    <span class="hljs-comment">//4、小王将商品减了30元，存入了数据库</span><br>    p2.setPrice(p2.getPrice() - <span class="hljs-number">30</span>);<br>    <span class="hljs-keyword">int</span> result2 = productMapper.updateById(p2);<br>    System.out.println(<span class="hljs-string">&quot;小王修改结果：&quot;</span> + result2);<br>    <span class="hljs-comment">//最后的结果</span><br>    Product p3 = productMapper.selectById(<span class="hljs-number">1L</span>);<br>    System.out.println(<span class="hljs-string">&quot;最后的结果：&quot;</span> + p3.getPrice());<br>&#125;<br></code></pre></td></tr></table></figure>

<h2 id="2、乐观锁方案"><a href="#2、乐观锁方案" class="headerlink" title="2、乐观锁方案"></a>2、乐观锁方案</h2><p>数据库中添加version字段：取出记录时，获取当前version</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SELECT</span> id,`name`,price,`version` <span class="hljs-keyword">FROM</span> product <span class="hljs-keyword">WHERE</span> id<span class="hljs-operator">=</span><span class="hljs-number">1</span><br></code></pre></td></tr></table></figure>

<p>更新时，version + 1，如果where语句中的version版本不对，则更新失败</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql">UPDATE product <span class="hljs-keyword">SET</span> price<span class="hljs-operator">=</span>price<span class="hljs-operator">+</span><span class="hljs-number">50</span>, `version`<span class="hljs-operator">=</span>`version` <span class="hljs-operator">+</span> <span class="hljs-number">1</span> <span class="hljs-keyword">WHERE</span> id<span class="hljs-operator">=</span><span class="hljs-number">1</span> <span class="hljs-keyword">AND</span> `version`<span class="hljs-operator">=</span><span class="hljs-number">1</span><br></code></pre></td></tr></table></figure>

<p>接下来介绍如何在Mybatis-Plus项目中，使用乐观锁：</p>
<h2 id="3、乐观锁实现流程"><a href="#3、乐观锁实现流程" class="headerlink" title="3、乐观锁实现流程"></a>3、乐观锁实现流程</h2><p><em><strong>*step1：修改实体类*</strong></em></p>
<p>添加 @Version 注解</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Version</span><br><span class="hljs-keyword">private</span> Integer version;<br></code></pre></td></tr></table></figure>

<p><strong>step2：添加乐观锁插件</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs java">interceptor.addInnerInterceptor(<span class="hljs-keyword">new</span> OptimisticLockerInnerInterceptor());<span class="hljs-comment">//乐观锁</span><br></code></pre></td></tr></table></figure>

<p><strong>step3：重新执行测试</strong></p>
<p>小王的修改失败！</p>
<h2 id="4、优化流程"><a href="#4、优化流程" class="headerlink" title="4、优化流程"></a>4、优化流程</h2><p>失败后重试</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">if</span>(result2 == <span class="hljs-number">0</span>)&#123;<span class="hljs-comment">//更新失败，重试</span><br>    System.out.println(<span class="hljs-string">&quot;小王重试&quot;</span>);<br>    <span class="hljs-comment">//重新获取数据</span><br>    p2 = productMapper.selectById(<span class="hljs-number">1L</span>);<br>    <span class="hljs-comment">//更新</span><br>    p2.setPrice(p2.getPrice() - <span class="hljs-number">30</span>);<br>    productMapper.updateById(p2);<br>&#125;<br></code></pre></td></tr></table></figure>
            </div>
            <hr>
            <div>
              <div class="post-metas mb-3">
                
                  <div class="post-meta mr-3">
                    <i class="iconfont icon-category"></i>
                    
                      <a class="hover-with-bg" href="/categories/MybatisPlus/">MybatisPlus</a>
                    
                  </div>
                
                
                  <div class="post-meta">
                    <i class="iconfont icon-tags"></i>
                    
                      <a class="hover-with-bg" href="/tags/MybatisPlus/">MybatisPlus</a>
                    
                  </div>
                
              </div>
              
                <p class="note note-warning">
                  
                    本博客目前大部分文章都是参考尚硅谷或者马士兵教育的学习资料！<a href="http://www.atguigu.com/" rel="nofollow noopener"官网地址！</a> 
                  
                </p>
              
              
                <div class="post-prevnext">
                  <article class="post-prev col-6">
                    
                    
                      <a href="/2022/01/20/MybatisPlus03/">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">Mybatis-plus条件构造器各种用法（三）</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                      <a href="/2022/01/15/Nginx/">
                        <span class="hidden-mobile">Nginx</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </article>
                </div>
              
            </div>

            
              <!-- Comments -->
              <article class="comments" id="comments" lazyload>
                
                  
                
                

              </article>
            
          </article>
        </div>
      </div>
    </div>
    
      <div class="d-none d-lg-block col-lg-2 toc-container" id="toc-ctn">
        <div id="toc">
  <p class="toc-header"><i class="iconfont icon-list"></i>&nbsp;目录</p>
  <div class="toc-body" id="toc-body"></div>
</div>

      </div>
    
  </div>
</div>

<!-- Custom -->


    

    
      <a id="scroll-top-button" aria-label="TOP" href="#" role="button">
        <i class="iconfont icon-arrowup" aria-hidden="true"></i>
      </a>
    

    
      <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v"
                 for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>
    

    
  </main>

  <footer class="text-center mt-5 py-3">

  <div class="footer-content">
     <a href="https://hexo.io" target="_blank" rel="nofollow noopener"><span>Hexo</span></a> <i class="iconfont icon-love"></i> <a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener"><span>Fluid</span></a> 
	<!--《添加网站运行时间 -->
<br/>

<span id="timeDate">载入天数...</span><span id="times">载入时分秒...</span>
<script>
var now = new Date(); 

function createtime() {
    //此处修改你的建站时间或者网站上线时间
    var grt = new Date('11/02/2021 21:39:00');
    now.setTime(now.getTime() + 250);
    days = (now - grt) / 1000 / 60 / 60 / 24;

    dnum = Math.floor(days);
    hours = (now - grt) / 1000 / 60 / 60 - (24 * dnum);
    hnum = Math.floor(hours);
    if (String(hnum).length == 1) {
        hnum = "0" + hnum;
    }
    minutes = (now - grt) / 1000 / 60 - (24 * 60 * dnum) - (60 * hnum);
    mnum = Math.floor(minutes);
    if (String(mnum).length == 1) {
        mnum = "0" + mnum;
    }
    seconds = (now - grt) / 1000 - (24 * 60 * 60 * dnum) - (60 * 60 * hnum) - (60 * mnum);
    snum = Math.round(seconds);
    if (String(snum).length == 1) {
        snum = "0" + snum;
    }
    document.getElementById("timeDate").innerHTML = " 本站已各种夹缝中安全运行 " + dnum + " 天 ";
    document.getElementById("times").innerHTML = hnum + " 小时 " + mnum + " 分 " + snum + " 秒";
}
setInterval("createtime()", 250);
</script>

<!-- 添加网站运行时间》-->
  </div>
  
  <div class="statistics">
    
    

    
      
        <!-- 不蒜子统计PV -->
        <span id="busuanzi_container_site_pv" style="display: none">
            总访问量 
            <span id="busuanzi_value_site_pv"></span>
             次
          </span>
      
      
        <!-- 不蒜子统计UV -->
        <span id="busuanzi_container_site_uv" style="display: none">
            总访客数 
            <span id="busuanzi_value_site_uv"></span>
             人
          </span>
      
    
  </div>


  

  
</footer>


  <!-- SCRIPTS -->
  
  <script  src="https://cdn.jsdelivr.net/npm/nprogress@0/nprogress.min.js" ></script>
  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/nprogress@0/nprogress.min.css" />

  <script>
    NProgress.configure({"showSpinner":false,"trickleSpeed":100})
    NProgress.start()
    window.addEventListener('load', function() {
      NProgress.done();
    })
  </script>


<script  src="https://cdn.jsdelivr.net/npm/jquery@3/dist/jquery.min.js" ></script>
<script  src="https://cdn.jsdelivr.net/npm/bootstrap@4/dist/js/bootstrap.min.js" ></script>
<script  src="/js/events.js" ></script>
<script  src="/js/plugins.js" ></script>

<!-- Plugins -->


  <script  src="/js/local-search.js" ></script>



  
    <script  src="/js/img-lazyload.js" ></script>
  



  



  
    <script  src="https://cdn.jsdelivr.net/npm/tocbot@4/dist/tocbot.min.js" ></script>
  
  
    <script  src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3/dist/jquery.fancybox.min.js" ></script>
  
  
    <script  src="https://cdn.jsdelivr.net/npm/anchor-js@4/anchor.min.js" ></script>
  
  
    <script defer src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js" ></script>
  



  <script defer src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" ></script>




  <script  src="https://cdn.jsdelivr.net/npm/typed.js@2/lib/typed.min.js" ></script>
  <script>
    (function (window, document) {
      var typing = Fluid.plugins.typing;
      var title = document.getElementById('subtitle').title;
      
      typing(title)
      
    })(window, document);
  </script>















<!-- 主题的启动项 保持在最底部 -->
<script  src="/js/boot.js" ></script>


</body>
</html>
